#include "EnvelopDetector.h"
#include "lang/StringFormat.hpp"
using namespace yzrilyzr_lang;
namespace yzrilyzr_dsp{
	EnvelopDetector::EnvelopDetector(){
		registerParamTimeMs("Attack", &attack);
		registerParamTimeMs("Hold", &hold);
		registerParamTimeMs("Release", &release);
		registerParamTimeMs("RmsWindow", &rmsWindow);
		static const char * names[2]={"PEAK", "RMS"};
		registerParamEnum("Type", &type, names, 2);
	}
	EnvelopDetector::EnvelopDetector(u_time_ms attack, u_time_ms hold, u_time_ms release, int type, u_time_ms rmsWindow) :
		attack(attack),
		hold(hold),
		release(release),
		type(type),
		rmsWindow(rmsWindow){}
	void EnvelopDetector::init(u_sample_rate sampleRate){
		deltaTime=1000.0 / static_cast<u_sample>(sampleRate);
		if(type == RMS){
			rmsC.init(sampleRate);
			rmsC.setBufferSize(static_cast<u_index>(ceil(rmsWindow / 1000.0 * sampleRate)));
		}
	}
	void EnvelopDetector::resetMemory(){
		envValue=0;
		holdTimer=0.0f;
		rmsC.resetMemory();
	}
	std::shared_ptr<DSP> EnvelopDetector::cloneDSP(){
		return std::make_shared<EnvelopDetector>(attack, hold, release, type, rmsWindow);
	}
	void EnvelopDetector::cloneParam(DSP * obj1){
		if(auto other=dynamic_cast<EnvelopDetector *>(obj1)){
			attack=other->attack;
			hold=other->hold;
			release=other->release;
			type=other->type;
		}
	}
	inline u_sample EnvelopDetector::procDsp(u_sample v){
		u_sample currentMax;

		   // 获取当前信号值
		if(type == PEAK){
			currentMax=std::abs(v);
		} else if(type == RMS){
			rmsC.procDsp(v);
			currentMax=rmsC.rms();
			if(isnan(currentMax))resetMemory();
		} else{
			currentMax=0.0f;
		}

		// 包络检测算法
		if(currentMax > envValue){
			// 攻击阶段 - 信号上升
			if(attack == 0){
				envValue=currentMax;
			} else{
				float attackCoeff=std::exp(-deltaTime / attack);
				envValue=currentMax + attackCoeff * (envValue - currentMax);
			}
			holdTimer=0.0f; // 重置保持计时器
		} else{
			if(holdTimer < hold){
				// 保持阶段 - 保持当前值
				holdTimer+=deltaTime;
			} else{
				// 释放阶段 - 信号下降
				if(release == 0){
					envValue=0;
				} else{
					float releaseCoeff=std::exp(-deltaTime / release);
					envValue=releaseCoeff * envValue;
				}
			}
		}
		return v;//不影响dsp链
	}
	u_sample EnvelopDetector::getEnvValue() const{
		return envValue;
	}
	String EnvelopDetector::toString()const{
		return StringFormat::object2string("EnvelopDetector", attack, hold, release, type, rmsWindow);
	}
}